<?php
/**
 * CK 开发框架
 * User: Clake
 * Date: 2017/7/25
 * Time: 10:15
 */

namespace CK\Util;


use CK\Core\Base;

class SSLCipher extends Base {
    /**
     * @var SSLCipher
     */
    private static $_instance;

    public static function inst($key='ck_core') {
        if (!isset(self::$_instance)) {
            self::$_instance = new self($key);
        } else {
            if ($key !== self::$_instance->getSecureKey()) {
                self::$_instance->setSecureKey($key);
            }
        }
        return self::$_instance;
    }

    private $_secure_key;
    private $_iv;
    private $_openssl_chiper_type = 'AES-128-CBC';
    private $_block_size;

    public function __construct($key) {
        $this->setSecureKey($key);
    }

    /**
     * 加密一个字符串
     *
     * @param $input
     *
     * @return string
     */
    public function encrypt($input) {
        $input = $this->addPkcs7Padding($input,$this->_block_size);
        $cipher_str = openssl_encrypt($input, $this->_openssl_chiper_type, $this->_secure_key,OPENSSL_ZERO_PADDING, $this->_iv);
        return $cipher_str;
    }

    /**
     * 解密一个字符串
     * @param $input
     *
     * @return string
     */
    public function decrypt($input) {
        $cipher_str = openssl_decrypt($input, $this->_openssl_chiper_type, $this->_secure_key,OPENSSL_ZERO_PADDING, $this->_iv);
        $cipher_str = $this->stripPkcs7Padding($cipher_str);
        return trim($cipher_str);
    }
    /**
     * 得到当前加密密钥
     * @return string
     */
    public function getSecureKey() {
        return $this->_secure_key;
    }

    /**
     * 设置当前加密密钥
     * @param string $secure_key
     */
    public function setSecureKey($secure_key) {
        $key_len = strlen($secure_key);
        if ($key_len < 16) {
            $this->_openssl_chiper_type = 'AES-128-CBC';
            $this->_block_size = 16;
            $secure_key = str_pad($secure_key,16,'c',STR_PAD_RIGHT);
        } elseif ($key_len > 16 && $key_len <= 24) {
            $this->_openssl_chiper_type = 'AES-192-CBC';
            $this->_block_size = 24;
            $secure_key = str_pad($secure_key,24,'c',STR_PAD_RIGHT);
        } elseif ($key_len > 24 && $key_len <= 32) {
            $this->_openssl_chiper_type = 'AES-256-CBC';
            $this->_block_size = 32;
            $secure_key = str_pad($secure_key,32,'c',STR_PAD_RIGHT);
        }
        $this->_iv = $secure_key;
        $this->_secure_key = $secure_key;
    }

    public function setIv($iv) {
        $this->_iv = $iv;
    }

    public function getIv() {
        return $this->_iv;
    }

    public function hexToStr($hex){//十六进制转字符串
        $string="";
        for($i=0;$i<strlen($hex)-1;$i+=2)
            $string.=chr(hexdec($hex[$i].$hex[$i+1]));
        return  $string;
    }

    public function strToHex($string){//字符串转十六进制
        $hex="";
        $tmp="";
        for($i=0;$i<strlen($string);$i++)
        {
            $tmp = dechex(ord($string[$i]));
            $hex.= strlen($tmp) == 1 ? "0".$tmp : $tmp;
        }
        $hex=strtoupper($hex);
        return $hex;
    }

    /**
     * pkcs7补码
     * @param string $string  明文
     * @param int $blocksize Blocksize , 以 byte 为单位
     * @return String
     */
    private function addPkcs7Padding($string, $blocksize = 32) {
        $len = strlen($string); //取得字符串长度
        $pad = $blocksize - ($len % $blocksize); //取得补码的长度
        $string .= str_repeat(chr($pad), $pad); //用ASCII码为补码长度的字符， 补足最后一段
        return $string;
    }

    /**
     * 除去pkcs7 padding
     *
     * @param string string 解密后的结果
     *
     * @return String
     */
    private function stripPkcs7Padding($string){
        $slast = ord(substr($string, -1));
        $slastc = chr($slast);

        if(preg_match("/$slastc{".$slast."}/", $string)){
            $string = substr($string, 0, strlen($string)-$slast);
            return $string;
        } else {
            return false;
        }
    }
}